package storage.manager;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.Serializer;

import core.engine.systemDBEngine;
import core.exceptions.DBEngineException;
import storage.StorageException;
import storage.io.FileManager;

/**
 * 数据库管理器，负责数据库的创建、打开、关闭、删除等操作
 * 同时管理用户与数据库的映射关系
 */
public class DatabaseManager {
    // 可重入锁控制并发访问
    public static final ReentrantLock dbLock = new ReentrantLock(true);

    // 当前活动的数据库名称和所有者
    private static String currentDatabaseName = null;
    private static String currentDatabaseOwner = null;

    // 当前操作的用户线程本地存储
    private static final ThreadLocal<String> currentUserThreadLocal = new ThreadLocal<>();

    // 内部类用于包装DB实例和引用计数
    static class DBReference {
        DB db;
        int referenceCount;

        DBReference(DB db) {
            this.db = db;
            this.referenceCount = 1; // Initialized with one reference
        }

        synchronized void incrementReference() {
            this.referenceCount++;
        }

        synchronized void decrementReference() {
            this.referenceCount--;
        }

        synchronized boolean hasNoReferences() {
            return this.referenceCount <= 0;
        }

        synchronized DB getDbInstance() {
            return this.db;
        }

        synchronized boolean isDbClosed() {
            return this.db == null || this.db.isClosed();
        }

        synchronized void closeInternalDB(String dbNameForLog) {
            if (db != null && !db.isClosed()) {
                try {
                    db.close();
                    System.out.println("💾 DB instance for '" + dbNameForLog + "' closed by DatabaseManager.");
                } catch (Exception e) {
                    System.err.println("❗ Error closing DB '" + dbNameForLog + "': " + e.getMessage());
                }
            }
            this.db = null; // Help GC
        }
    }

    // 打开的数据库实例缓存，使用新的DBReference类型
    private static final Map<String, DBReference> openDatabases = new ConcurrentHashMap<>();

    // 数据库变更监听器集合
    private static final Set<Runnable> databaseChangeListeners = ConcurrentHashMap.newKeySet();

    /**
     * 添加数据库变更监听器
     * @param listener 监听器回调
     */
    public static void addDatabaseChangeListener(Runnable listener) {
        databaseChangeListeners.add(listener);
    }

    /**
     * 移除数据库变更监听器
     * @param listener 监听器回调
     */
    public static void removeDatabaseChangeListener(Runnable listener) {
        databaseChangeListeners.remove(listener);
    }

    /**
     * 通知所有监听器数据库已变更
     */
    private static void notifyDatabaseChanged() {
        databaseChangeListeners.forEach(Runnable::run);
    }

    // Helper method for creating a standardized cache key
    private static String getDatabaseCacheKey(String ownerName, String dbName) {
        if (dbName == null) return null; // Or throw exception
        if (ownerName == null && "system_db".equals(dbName)) { // system_db's owner is "system"
            ownerName = "system";
        }
        if (ownerName == null) { // Should not happen for user databases if logic is correct
            // This case needs to be decided: throw error or default?
            // For now, let's assume ownerName will always be provided for user DBs.
            // If dbName is system_db, ownerName should be "system".
            System.err.println("[WARN] DatabaseManager.getDatabaseCacheKey: ownerName is null for db: " + dbName + ". This might lead to issues.");
            return dbName; // Fallback, might be problematic
        }
        return ownerName + "." + dbName;
    }

    /**
     * 设置当前操作用户
     *
     * @param username 用户名
     */
    public static void setCurrentUser(String username) {
        currentUserThreadLocal.set(username);
        if (username != null) {
            System.out.println("✅ 数据库管理器当前用户已设置为: " + username);
        } else {
            currentUserThreadLocal.remove();
        }
    }

    /**
     * 获取当前操作用户
     *
     * @return 当前用户名
     */
    public static String getCurrentUser() {
        return currentUserThreadLocal.get();
    }

    /**
     * 获取数据库实例
     * 如果数据库已经打开，则返回缓存的实例并增加引用计数。
     * 否则打开数据库，缓存实例（引用计数为1），并返回它。
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName 数据库名称
     * @return 返回 DB 实例供事务使用
     * @throws StorageException 如果数据库不存在、用户无权访问或无法打开数据库
     */
    public static DB getDatabase(String ownerName, String dbName) throws StorageException {
        if (dbName == null || dbName.trim().isEmpty()) {
            throw new StorageException("数据库名称不能为空");
        }
        if (ownerName == null || ownerName.trim().isEmpty()) {
            // "system_db" is a special case where its owner is implicitly "system"
            if (!"system_db".equals(dbName)) {
                throw new StorageException("数据库所有者名称不能为空 (for non-system_db)");
            }
            ownerName = "system"; // Default owner for system_db
        }

        final String effectiveOwnerName = ownerName; // for use in lambdas/inner classes

        // 权限检查 (对于非系统数据库)
        // system_db access is typically restricted at a higher level or by its nature (e.g. admin only)
        // However, hasDatabasePermission itself handles admin override.
            String currentUser = getCurrentUser();
        if (currentUser == null && !"system_db".equals(dbName)) { // Allow system access for system_db even if no "user" session
            throw new StorageException("未登录用户无法访问数据库: " + effectiveOwnerName + "." + dbName);
        }
        // Allow access to system_db if current user is admin, or if no user (e.g. system init)
        // For user databases, permission must be checked.
        if (!"system_db".equals(dbName)) {
            if (!hasDatabasePermission(currentUser, effectiveOwnerName, dbName)) {
                throw new StorageException("数据库 '" + effectiveOwnerName + "." + dbName + "' 不存在或用户 '" + currentUser + "' 无权访问。");
            }
        } else { // For system_db
            if (currentUser != null && !security.auth.UserManager.isAdmin(currentUser)) {
                 // This check might be redundant if Session layer already blocks non-admins from USE system_db
                 System.out.println("[INFO] DatabaseManager.getDatabase: Non-admin user '" + currentUser + "' attempting to get system_db instance. Access relies on higher-level checks.");
            }
        }

        String cacheKey = getDatabaseCacheKey(effectiveOwnerName, dbName);
        dbLock.lock(); // 加锁
        try {
            DBReference dbRef = openDatabases.get(cacheKey);

            if (dbRef != null && !dbRef.isDbClosed()) {
                dbRef.incrementReference();
                System.out.println("[DEBUG] DatabaseManager: Returning cached DB instance for '" + cacheKey + "'. Ref count: " + dbRef.referenceCount);
                return dbRef.getDbInstance();
            } else if (dbRef != null) {
                System.out.println("[WARN] DatabaseManager: Cached DB instance for '" + cacheKey + "' was closed or null. Removing invalid entry.");
                openDatabases.remove(cacheKey);
            }

            System.out.println("[INFO] DatabaseManager: Cache miss or invalid DB for '" + cacheKey + "'. Attempting to open/reopen.");
            String dbPath = getPhysicalDbPath(effectiveOwnerName, dbName);
            File dbFile = new File(dbPath);

            // ----> 调整后的诊断代码 <----
            System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Target DB file path for DBMaker: " + dbFile.getAbsolutePath());
            File parentDir = dbFile.getParentFile();
            if (parentDir != null) {
                System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Parent directory: " + parentDir.getAbsolutePath());
                System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Does parent directory exist? " + parentDir.exists());
                System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Is parent directory a directory? " + parentDir.isDirectory());
                System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Parent directory writable? " + parentDir.canWrite());

                // 确保父目录存在 (虽然 createDatabase 应该已经做了，但双重检查无害)
                if (!parentDir.exists()) {
                    System.out.println("[DIAGNOSTIC] DatabaseManager.getDatabase: Parent directory does not exist. Attempting to create it.");
                    if (parentDir.mkdirs()) {
                        System.out.println("[DIAGNOSTIC_SUCCESS] DatabaseManager.getDatabase: Parent directory created: " + parentDir.getAbsolutePath());
                    } else {
                        System.err.println("[DIAGNOSTIC_ERROR] DatabaseManager.getDatabase: Failed to create parent directory: " + parentDir.getAbsolutePath() + ". DBMaker will likely fail.");
                        throw new StorageException("无法创建数据库的父目录: " + parentDir.getAbsolutePath());
                    }
                }
            } else {
                System.err.println("[DIAGNOSTIC_ERROR] DatabaseManager.getDatabase: Parent directory is null for dbFile: " + dbFile.getAbsolutePath());
                throw new StorageException("无法确定数据库文件的父目录: " + dbFile.getAbsolutePath());
            }
            // ----> 调整后的诊断代码结束 <----

            java.io.PrintStream originalOut = System.out;
            DB newDbInstance;
            try {
                System.setOut(new java.io.PrintStream(new java.io.OutputStream() {
                    public void write(int b) { /* NOP */ }
                }));

                System.out.println("[DEBUG] DatabaseManager: Opening/Creating new DB instance with DBMaker for '" + cacheKey + "' at path: " + dbPath);
                newDbInstance = DBMaker.fileDB(dbFile)
                        .fileLockDisable()
                        .closeOnJvmShutdown()
                        .cleanerHackEnable()
                        .fileMmapEnableIfSupported()
                        .transactionEnable()
                        .make();

                dbRef = new DBReference(newDbInstance);
                openDatabases.put(cacheKey, dbRef);
                System.out.println("[INFO] DatabaseManager: DB instance for '" + cacheKey + "' opened/created and cached. Ref count: " + dbRef.referenceCount);
                return newDbInstance;

            } catch (Exception e) {
                System.err.println("❗ DatabaseManager: Failed to open/create database with DBMaker for '" + cacheKey + "' at path '"+ dbPath + "': " + e.getMessage());
                System.err.println("❗ ---- DBMaker Original Exception Stack Trace ----");
                e.printStackTrace();
                System.err.println("❗ ---- End of DBMaker Original Exception ----");
                throw new StorageException("DBMaker无法打开或创建数据库 '" + cacheKey + "': " + e.getMessage(), e);
            } finally {
                System.setOut(originalOut);
            }
        } finally {
            dbLock.unlock();
        }
    }

    /**
     * 获取数据库的物理路径
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName 数据库名称
     * @return 数据库文件的物理路径
     */
    private static String getPhysicalDbPath(String ownerName, String dbName) throws StorageException {
        java.io.PrintStream originalOut = System.out;
        String result;

        try {
            System.setOut(new java.io.PrintStream(new java.io.OutputStream() {
                public void write(int b) { }
            }));

            if ("system_db".equals(dbName)) {
                // Owner of system_db is "system" or handled implicitly
                result = Paths.get(FileManager.DB_ROOT, dbName + FileManager.DB_EXTENSION).toString();
                return result;
            }

            // For user databases, ownerName must be provided
            if (ownerName == null || ownerName.trim().isEmpty()) {
                throw new StorageException("数据库所有者名称不能为空 (for non-system_db path resolution)");
            }

            result = Paths.get(FileManager.DB_ROOT, "USER", ownerName, dbName, dbName + FileManager.DB_EXTENSION).toString();
            return result;
        } finally {
            System.setOut(originalOut);
        }
    }

    /**
     * 设置当前数据库上下文（由Session调用）
     *
     * @param ownerName 数据库所有者的名称
     * @param dbName 数据库名称
     */
    public static void setCurrentDatabase(String ownerName, String dbName) {
        if (dbName == null) {
            currentDatabaseName = null;
            currentDatabaseOwner = null;
            System.out.println("ℹ️ DatabaseManager: 当前数据库上下文已清除。");
        } else {
            // "system_db" owner defaults to "system" if not provided, but Session should provide it.
            String effectiveOwner = ownerName;
            if (effectiveOwner == null && "system_db".equals(dbName)) {
                effectiveOwner = "system";
            }

            if (effectiveOwner == null || effectiveOwner.trim().isEmpty()){
                 System.err.println("[WARN] DatabaseManager.setCurrentDatabase: Owner name is null or empty for DB: " + dbName + ". Context might be incomplete.");
                 // Decide if an error should be thrown or if dbName alone is acceptable in some fallback scenario
                 currentDatabaseOwner = null; // Or some default / error marker
            } else {
                 currentDatabaseOwner = effectiveOwner;
            }
            currentDatabaseName = dbName;
            System.out.println("ℹ️ DatabaseManager: 当前数据库上下文已设置为: " + (currentDatabaseOwner != null ? currentDatabaseOwner + "." : "") + currentDatabaseName);
        }
    }

    /**
     * 获取当前数据库的名称（主要用于遗留代码或调试）
     * @return 当前数据库名称，可能为null
     */
    public static String getCurrentDatabaseName() {
        return currentDatabaseName;
    }

    /**
     * 获取当前数据库的所有者名称（主要用于遗留代码或调试）
     * @return 当前数据库所有者名称，可能为null
     */
    public static String getCurrentDatabaseOwner() {
        return currentDatabaseOwner;
    }

    /**
     * 关闭指定的数据库实例，减少其引用计数。如果引用计数为0，则实际关闭DB连接。
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName    要关闭的数据库的名称
     */
    public static void closeDatabase(String ownerName, String dbName) {
        if (dbName == null || dbName.trim().isEmpty()) {
            System.err.println("[WARN] DatabaseManager.closeDatabase: dbName is null or empty. Operation aborted.");
            return;
        }
         String effectiveOwnerName = ownerName;
        if (effectiveOwnerName == null && "system_db".equals(dbName)) {
            effectiveOwnerName = "system";
        }
        if (effectiveOwnerName == null && !"system_db".equals(dbName)) {
             System.err.println("[WARN] DatabaseManager.closeDatabase: ownerName is null for non-system_db: " + dbName + ". Cannot reliably close.");
            return;
        }

        String cacheKey = getDatabaseCacheKey(effectiveOwnerName, dbName);
        dbLock.lock();
        try {
            DBReference dbRef = openDatabases.get(cacheKey);
            if (dbRef != null) {
                dbRef.decrementReference();
                System.out.println("[INFO] DatabaseManager: Decremented reference count for DB '" + cacheKey + "'. New count: " + dbRef.referenceCount);
                if (dbRef.hasNoReferences()) {
                    System.out.println("[INFO] DatabaseManager: Reference count for DB '" + cacheKey + "' is zero. Closing DB instance.");
                    dbRef.closeInternalDB(cacheKey);
                    openDatabases.remove(cacheKey);
                }
            } else {
                System.out.println("[WARN] DatabaseManager.closeDatabase: No open DB instance found for '" + cacheKey + "' to close.");
            }
        } finally {
            dbLock.unlock();
        }
    }

    /**
     * 创建新数据库。
     * 此方法现在主要由 SQLExecutor 调用，并传入创建者信息。
     *
     * @param dbName   数据库名称
     * @param creatorUsername 创建者的用户名 (现在是必须的)
     * @return 1 表示成功，0 表示失败，-1 表示已存在
     */
    public static int createDatabase(String dbName, String creatorUsername) {
        if (dbName == null || dbName.trim().isEmpty() || creatorUsername == null || creatorUsername.trim().isEmpty()) {
            System.err.println("❌ 创建数据库失败：数据库名称和创建者用户名不能为空。");
            return 0; // 失败
        }
        if ("system_db".equalsIgnoreCase(dbName)) {
            System.err.println("❌ 创建数据库失败：不能创建名为 'system_db' 的数据库，此为保留名称。");
            return 0; // 失败
        }

        dbLock.lock();
        try {
            // 检查数据库是否已存在 (使用新的 databaseExists 方法)
            if (databaseExists(creatorUsername, dbName)) {
                System.err.println("❌ 创建数据库失败：数据库 '" + creatorUsername + "." + dbName + "' 已存在。");
                return -1; // 表示已存在
            }

            // 创建数据库物理目录结构
            // Path: DBMS_ROOT/USER/用户名/数据库名/
            Path dbUserPath = Paths.get(FileManager.DB_ROOT, "USER", creatorUsername);
            Path dbSpecificPath = dbUserPath.resolve(dbName);
            try {
                Files.createDirectories(dbSpecificPath);
                System.out.println("✅ 已创建数据库目录: " + dbSpecificPath.toString());
            } catch (IOException e) {
                System.err.println("❌ 创建数据库目录失败: " + dbSpecificPath.toString() + " - " + e.getMessage());
                return 0; // 失败
            }

            // 创建 .db 文件 (空文件，或由 DBMaker 首次访问时创建)
            // DBMaker.fileDB(...).make() 会在文件不存在时创建它。
            // 我们可以在这里尝试打开并立即关闭它来"创建"它并缓存。
            String dbFilePath = getPhysicalDbPath(creatorUsername, dbName);
            try {
                // 尝试获取（并因此创建/打开）数据库实例
                DB testDB = getDatabase(creatorUsername, dbName);
                // 成功获取后，立即释放它，因为createDatabase不应保持打开状态
                // getDatabase内部会将其放入openDatabases并计数为1，需要释放
                releaseDatabase(creatorUsername, dbName);

                // 在系统数据库中注册数据库信息
                systemDBEngine.addUserDatabaseMapping(creatorUsername, dbName);

                System.out.println("✅ 数据库 '" + creatorUsername + "." + dbName + "' 创建成功，文件位于: " + dbFilePath);
            notifyDatabaseChanged();
            return 1; // 成功
            } catch (StorageException | DBEngineException e) {
                System.err.println("❌ 数据库 '" + creatorUsername + "." + dbName + "' 创建过程中出错: " + e.getMessage());
                // 清理可能已创建的目录
                try {
                    FileManager.deleteDirectory(dbSpecificPath);
                    System.out.println("[INFO] DatabaseManager: Directory cleanup for failed DB creation attempted for: " + dbSpecificPath);
                } catch (Exception ex) {
                    System.err.println("⚠️ 清理失败目录时出错: " + dbSpecificPath + " - " + ex.getMessage());
                }
                return 0; // 失败
            }
        } finally {
            dbLock.unlock();
        }
    }

    /**
     * 删除数据库。
     * 执行者必须是数据库所有者，或系统管理员。
     *
     * @param ownerName 数据库的预期所有者
     * @param dbName    要删除的数据库名称
     * @return 1 表示成功，0 表示失败
     */
    public static int deleteDatabase(String ownerName, String dbName) {
        String currentUser = getCurrentUser();
        if (currentUser == null) {
            System.err.println("❌ 删除数据库失败：用户未登录。");
            return 0;
        }
         if (ownerName == null || ownerName.trim().isEmpty() || dbName == null || dbName.trim().isEmpty()) {
            System.err.println("❌ 删除数据库失败：所有者名称和数据库名称不能为空。");
            return 0;
        }

        if ("system_db".equalsIgnoreCase(dbName)) {
            System.err.println("❌ 删除数据库失败：系统数据库 'system_db' 不能被删除。");
            return 0;
        }

        dbLock.lock();
        try {
            // 1. 从 systemDBEngine 获取数据库信息以验证所有者和获取物理路径
            // systemDBEngine.deleteDatabaseMetadata 会进行权限校验并返回 actualCreator (也是 ownerName)
            String actualCreatorForPath;
            try {
                actualCreatorForPath = systemDBEngine.deleteDatabaseMetadata(ownerName, dbName);
                if (actualCreatorForPath == null || !actualCreatorForPath.equals(ownerName)) {
                     System.err.println("❌ 删除数据库元数据时返回的创建者与预期不符。 Owner: " + ownerName + ", Got: " + actualCreatorForPath);
                     return 0; // Should not happen if deleteDatabaseMetadata is correct
                }
            } catch (DBEngineException e) {
                System.err.println("❌ 删除数据库元数据失败: " + e.getMessage());
                return 0;
            }

            // 2. 如果元数据删除成功，关闭并从缓存中移除数据库实例（如果已打开）
            String cacheKey = getDatabaseCacheKey(ownerName, dbName);
            DBReference dbRef = openDatabases.get(cacheKey);
            if (dbRef != null) {
                System.out.println("[INFO] DatabaseManager: Force closing DB '" + cacheKey + "' due to deletion.");
                dbRef.closeInternalDB(cacheKey); // 强制关闭，无视引用计数
                openDatabases.remove(cacheKey);
                System.out.println("[INFO] DatabaseManager.deleteDatabase: DB instance '" + cacheKey + "' closed and removed from cache.");
            }

            // 3. 删除物理文件/目录
            // Path: DBMS_ROOT/USER/用户名/数据库名/
            Path dbSpecificPath = Paths.get(FileManager.DB_ROOT, "USER", actualCreatorForPath, dbName);
            try {
                if (FileManager.deleteDirectory(dbSpecificPath)) {
                    System.out.println("✅ 已成功删除数据库目录及其内容: " + dbSpecificPath.toString());
                } else {
                    System.err.println("❌ 删除数据库物理文件/目录失败: " + dbSpecificPath.toString() + ". The directory might not exist or an error occurred.");
                    // 根据 FileManager.deleteDirectory 的实现，如果目录不存在，它也可能返回 false 或 true。
                    // 如果元数据已删除但物理文件删除失败，这仍然是一个问题。
                    // 保持返回0，表示操作未完全成功。
                    return 0; // 标记为失败，因为物理删除未完成或有疑问
                }
                // System.out.println("[INFO] DatabaseManager: Physical directory cleanup for DB deletion skipped (deleteDirectory commented out): " + dbSpecificPath);
                // System.out.println("✅ 已成功删除数据库目录及其内容 (模拟，实际删除被注释): " + dbSpecificPath.toString());
            } catch (Exception e) { // Catches any other unexpected exception from deleteDirectory itself, though it should handle its own IOExceptions.
                System.err.println("❌ 调用 FileManager.deleteDirectory 时发生意外错误: " + dbSpecificPath.toString() + " - " + e.getMessage());
                return 0; // 标记为失败
            }

            // 在删除元数据和物理目录之前，尝试显式删除 .wal 文件
            // 这有助于确保在目录删除前，.wal 文件（如果存在且未被 MapDB 自动处理）被尝试移除
            try {
                String dbPhysicalPath = getPhysicalDbPath(ownerName, dbName); // e.g., .../dbname.db
                Path walPath = Paths.get(dbPhysicalPath + ".wal"); // Common .wal extension
                Path walPath0 = Paths.get(dbPhysicalPath + ".wal.0"); // Another common variant

                if (Files.exists(walPath)) {
                    Files.delete(walPath);
                    System.out.println("[INFO] DatabaseManager.deleteDatabase: Successfully deleted WAL file: " + walPath);
                }
                if (Files.exists(walPath0)) {
                    Files.delete(walPath0);
                    System.out.println("[INFO] DatabaseManager.deleteDatabase: Successfully deleted WAL file: " + walPath0);
                }
            } catch (IOException e) {
                System.err.println("⚠️ DatabaseManager.deleteDatabase: Error attempting to explicitly delete .wal file for " + cacheKey + ": " + e.getMessage());
                // Continue with deletion process, as FileManager.deleteDirectory will also attempt cleanup
            } catch (Exception e) {
                System.err.println("⚠️ DatabaseManager.deleteDatabase: Unexpected error during explicit .wal file deletion for " + cacheKey + ": " + e.getMessage());
            }

            System.out.println("✅ 数据库 '" + ownerName + "." + dbName + "' 已成功删除。");
            notifyDatabaseChanged();
            return 1; // 成功
        } finally {
            dbLock.unlock();
        }
    }

    /**
     * 检查数据库是否存在。
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName    数据库名称
     * @return 如果数据库存在则返回 true，否则 false
     */
    public static boolean databaseExists(String ownerName, String dbName) {
        if (dbName == null || dbName.trim().isEmpty()) return false;
        String effectiveOwnerName = ownerName;
        if (effectiveOwnerName == null && "system_db".equals(dbName)) {
            effectiveOwnerName = "system";
        }
         if (effectiveOwnerName == null && !"system_db".equals(dbName)) {
            System.err.println("[WARN] databaseExists check with null owner for non-system_db: " + dbName);
            return false; // Or handle as error
        }

        try {
            // system_db always "exists" conceptually if the system is running.
            // Its physical existence is checked by getDatabase if needed.
            if ("system_db".equals(dbName) && "system".equals(effectiveOwnerName)) {
                // Check physical file for system_db to be more robust
                Path sysDbPath = Paths.get(FileManager.DB_ROOT, "system_db" + FileManager.DB_EXTENSION);
                return Files.exists(sysDbPath);
            }

            // For user databases, check metadata and physical path.
            Map<String, Object> dbInfo = systemDBEngine.getDatabaseInfo(effectiveOwnerName, dbName); // Needs new signature in systemDBEngine
            if (dbInfo == null || dbInfo.isEmpty()) {
            return false;
        }
            String physicalPath = (String) dbInfo.get("physicalPath");
            if (physicalPath == null || !Files.exists(Paths.get(physicalPath))) {
                // Metadata might exist but physical files are gone. Treat as non-existent or corrupted.
                // Optionally, log this inconsistency.
                System.err.println("[WARN] Database '" + effectiveOwnerName + "." + dbName + "' metadata found, but physical file missing: " + physicalPath);
                return false;
            }
            return true;
        } catch (Exception e) {
            System.err.println("检查数据库 '" + effectiveOwnerName + "." + dbName + "' 存在性时出错: " + e.getMessage());
            return false;
        }
    }

    /**
     * 显示指定用户拥有或有权访问的所有数据库。
     * 如果没有指定用户名，则尝试显示当前会话用户的数据库。
     *
     * @param username 用户名 (可选)
     */
    public static void showDatabases(String... username) {
        String targetUser;
        if (username.length > 0 && username[0] != null && !username[0].isEmpty()) {
            targetUser = username[0];
        } else {
            targetUser = getCurrentUser();
        }

        if (targetUser == null) {
            System.out.println("无法确定用户，无法显示数据库列表。");
            return;
        }

        System.out.println("用户 [" + targetUser + "] 可访问的数据库列表:");

        // Use systemDBEngine to get all database information
        // This needs a way to get ALL db_info_map entries from systemDBEngine
        Map<String, Map<String, Object>> allDbInfo = systemDBEngine.getAllDatabaseInfo(); // Assuming this method exists/is added

        if (allDbInfo.isEmpty()) {
            System.out.println("  (无数据库)");
                return;
            }

        boolean found = false;
        for (Map.Entry<String, Map<String, Object>> entry : allDbInfo.entrySet()) {
            String dbKey = entry.getKey(); // Format "DB:owner:dbName"
            Map<String, Object> dbInfo = entry.getValue();

            if (!dbKey.startsWith("DB:")) continue; // Skip malformed keys

            String[] keyParts = dbKey.substring(3).split(":", 2);
            if (keyParts.length < 2) continue; // Skip malformed keys

            String owner = keyParts[0];
            String dbName = keyParts[1];

            // Check if the targetUser has permission
            if (hasDatabasePermission(targetUser, owner, dbName)) {
                String creator = (String) dbInfo.get("creator");
                String createTime = (String) dbInfo.get("createTime");
                System.out.println("  - " + owner + "." + dbName + " (创建者: " + creator + ", 创建时间: " + createTime + ")");
                found = true;
            }
        }

        if (!found) {
            System.out.println("  (无权访问任何数据库或无数据库存在)");
        }
    }

    /**
     * 显示指定数据库中的所有表。
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName    数据库名称 (可选，如果为null，则尝试使用当前会话数据库)
     */
    public static void showTables(String ownerName, String dbName) {
        String effectiveOwner = ownerName;
        String effectiveDbName = dbName;

        if (effectiveDbName == null || effectiveDbName.trim().isEmpty()) {
            effectiveDbName = getCurrentDatabaseName();
            effectiveOwner = getCurrentDatabaseOwner(); // Get owner from session context too
        }

        if (effectiveOwner == null && "system_db".equals(effectiveDbName)) {
            effectiveOwner = "system";
        }

        if (effectiveDbName == null || effectiveDbName.trim().isEmpty() || effectiveOwner == null || effectiveOwner.trim().isEmpty()) {
            System.err.println("错误：未指定数据库或无法确定当前数据库上下文。请使用 USE 命令或提供数据库名。");
            return;
        }

        // 权限检查
        String currentUser = getCurrentUser();
        if (!hasDatabasePermission(currentUser, effectiveOwner, effectiveDbName)) {
             System.err.println("错误：用户 [" + currentUser + "] 无权访问数据库 [" + effectiveOwner + "." + effectiveDbName + "]。");
            return;
        }

        System.out.println("数据库 [" + effectiveOwner + "." + effectiveDbName + "] 中的表:");

        // 直接调用 TableManager.getTables，它现在可以处理事务和非事务上下文
        List<String> tables = TableManager.getTables(effectiveOwner, effectiveDbName);

        if (tables == null || tables.isEmpty()) { // getTables 现在应该返回空List而不是null，但以防万一
            System.out.println("  (无表)");
        } else {
            for (String tableName : tables) {
                System.out.println("  - " + tableName);
            }
        }
        // 不再需要手动 getDatabase/releaseDatabase，因为 TableManager.getTables 内部处理了
    }

    /**
     * 显示表结构信息
     *
     * @param tableName 表名
     * @param ownerName 数据库所有者 (可选)
     * @param dbName    数据库名称 (可选)
     */
    public static void showTableInfo(String tableName, String ownerName, String dbName) {
        String effectiveOwner = ownerName;
        String effectiveDbName = dbName;

        java.io.PrintStream tempNullStream = new java.io.PrintStream(new java.io.OutputStream() {
            @Override
            public void write(int b) throws IOException { /* NOP */ }
        });
        java.io.PrintStream originalOut = System.out;

        try {
            // Temporarily suppress console output from this method itself if not in verbose mode
            // This is tricky as verbose logging is in systemDBEngine. Assuming not verbose for now.
            // System.setOut(tempNullStream);

            if (effectiveDbName == null || effectiveDbName.isEmpty()) {
                effectiveDbName = getCurrentDatabaseName();
                effectiveOwner = getCurrentDatabaseOwner();
            }
            if (effectiveOwner == null && "system_db".equals(effectiveDbName)) {
                effectiveOwner = "system";
            }

            if (tableName == null || tableName.isEmpty() || effectiveDbName == null || effectiveDbName.isEmpty() || effectiveOwner == null || effectiveOwner.isEmpty()) {
                System.setOut(originalOut); // Restore before error print
                System.err.println("错误：必须提供表名、数据库所有者和数据库名。");
                return;
            }

            // 权限检查
            String currentUser = getCurrentUser();
             if (!hasDatabasePermission(currentUser, effectiveOwner, effectiveDbName)) {
                System.setOut(originalOut); // Restore before error print
                System.err.println("错误：用户 [" + currentUser + "] 无权访问数据库 [" + effectiveOwner + "." + effectiveDbName + "]。");
                return;
            }

            // System.setOut(originalOut); // Restore output for actual table info printing
            System.out.println("表 [" + tableName + "] 在数据库 [" + effectiveOwner + "." + effectiveDbName + "] 中的结构信息:");

            DB targetDB = null;
            try {
                targetDB = getDatabase(effectiveOwner, effectiveDbName);

                // 从 systemDBEngine 获取表结构元数据
                // Map<String, String> tableSchema = systemDBEngine.getTableSchema(effectiveOwner, effectiveDbName, tableName);
                // Assuming getTableSchema needs owner and dbName too.
                // For now, let's assume table schema is stored within the user's DB, not system DB.
                // This requires a schema storage mechanism within each user DB.
                // Let's say, each user DB has a map like "_schema_<tableName>"

                if (!targetDB.exists("_schema_" + tableName)) {
                     System.out.println("  表 '" + tableName + "' 的结构信息不存在或表不存在。");
                     return;
                }

                @SuppressWarnings("unchecked")
                Map<String, String> schema = (Map<String, String>) targetDB.hashMap("_schema_" + tableName, Serializer.STRING, Serializer.STRING).open();

                if (schema.isEmpty()) {
                    System.out.println("  (表结构为空或未定义)");
                } else {
                    System.out.println("  列名                 | 数据类型");
                    System.out.println("  ---------------------|-----------");
                    for (Map.Entry<String, String> entry : schema.entrySet()) {
                        System.out.printf("  %-20s | %s%n", entry.getKey(), entry.getValue());
                    }
                }
            } catch (StorageException e) {
                 System.err.println("显示表结构时出错: " + e.getMessage());
            } catch (Exception e) { // Catch other potential errors like ClassCastException from map
                 System.err.println("显示表结构时发生意外错误: " + e.getMessage());
                 e.printStackTrace();
            }
            finally {
                if (targetDB != null) {
                    releaseDatabase(effectiveOwner, effectiveDbName);
                }
            }
        } finally {
            // System.setOut(originalOut); // Ensure restoration
        }
    }

    /**
     * 关闭所有打开的数据库连接
     */
    public static void closeAllDatabases() {
        dbLock.lock();
        try {
            System.out.println("[INFO] DatabaseManager: Closing all open database instances...");
            // Create a copy of keys to avoid ConcurrentModificationException
            Set<String> cacheKeys = new HashSet<>(openDatabases.keySet());
            for (String cacheKey : cacheKeys) {
                DBReference dbRef = openDatabases.get(cacheKey);
                if (dbRef != null) {
                    System.out.println("[INFO] DatabaseManager: Force closing DB '" + cacheKey + "' during closeAll operation.");
                    dbRef.closeInternalDB(cacheKey); // Force close, ignore ref count
                }
            }
            openDatabases.clear();
            System.out.println("[INFO] DatabaseManager: All database instances cache cleared.");
        } finally {
            dbLock.unlock();
        }
    }

    /**
     * 检查用户是否有权访问特定数据库。
     *
     * @param accessingUserName  尝试访问的用户名
     * @param ownerName    数据库的预期所有者/创建者
     * @param dbName       数据库名称
     * @return 如果有权限则返回 true，否则 false
     */
    public static boolean hasDatabasePermission(String accessingUserName, String ownerName, String dbName) {
        if (accessingUserName == null || dbName == null || dbName.trim().isEmpty() || ownerName == null || ownerName.trim().isEmpty()) {
            return false;
        }

        // 系统管理员(1级权限)对所有数据库都有完全权限
        if (security.auth.UserManager.isAdmin(accessingUserName)) {
            // 注意：管理员仍然只能访问存在的数据库
            // 数据库是否存在的检查应该在getDatabase之前或内部完成
            return true;
        }

        // 普通用户不能直接访问 system_db (除非特定设计允许，目前设计是不允许)
        if ("system_db".equals(dbName) && "system".equals(ownerName)) {
            return false;
        }

        // 检查创建者是否就是访问者 (自己的数据库)
        if (accessingUserName.equals(ownerName)) {
            return true; // 创建者总是有权限访问自己的数据库
        }

        try {
            // 从系统数据库获取此数据库的信息
            Map<String, Object> dbInfo = systemDBEngine.getDatabaseInfo(ownerName, dbName);
            if (dbInfo == null || dbInfo.isEmpty()) {
                // 如果数据库信息不存在，则认为无权限或数据库不存在
                return false;
            }

            // 检查权限用户列表
            @SuppressWarnings("unchecked")
            Set<String> permissionedUsers = (Set<String>) dbInfo.get("permissionedUsers");
            if (permissionedUsers != null && permissionedUsers.contains(accessingUserName)) {
                return true;
            }

            // 检查用户授权数据库映射表 (检查2级权限)
            try {
                Map<String, Set<String>> authorizedDbs = systemDBEngine.getUserAuthorizedDatabases(accessingUserName);
                Set<String> ownerDbs = authorizedDbs.get(ownerName);
                if (ownerDbs != null && ownerDbs.contains(dbName)) {
                    return true;
                }
            } catch (Exception e) {
                System.err.println("检查用户授权数据库映射表时出错: " + e.getMessage());
                // 继续执行，不要因为这个检查失败就拒绝访问
            }

            return false; // 默认无权限
        } catch (Exception e) {
            System.err.println("检查数据库权限时出错 (" + accessingUserName + " on " + ownerName + "." + dbName + "): " + e.getMessage());
            return false;
        }
    }

    /**
     * 释放数据库实例的引用。如果引用计数降至零，则关闭数据库。
     * (之前叫 closeDatabase，但 release 更准确，因为它不总是关闭)
     *
     * @param ownerName 数据库所有者的用户ID
     * @param dbName    数据库名称
     */
    public static void releaseDatabase(String ownerName, String dbName) {
        // This is essentially the same as closeDatabase in terms of functionality
        // Renaming closeDatabase to releaseDatabase would be clearer if it doesn't always close.
        // For now, closeDatabase already implements the ref counting logic.
        closeDatabase(ownerName, dbName);
    }

    public static String getTablesAsString(String ownerName, String dbName) {
        StringBuilder result = new StringBuilder();
        String effectiveOwner = ownerName;
        String effectiveDbName = dbName;

        if (effectiveDbName == null || effectiveDbName.trim().isEmpty()) {
            effectiveDbName = getCurrentDatabaseName();
            effectiveOwner = getCurrentDatabaseOwner();
        }

        if (effectiveOwner == null && "system_db".equals(effectiveDbName)) {
            effectiveOwner = "system";
        }

        if (effectiveDbName == null || effectiveDbName.trim().isEmpty() || effectiveOwner == null || effectiveOwner.trim().isEmpty()) {
            return "错误：未指定数据库或无法确定当前数据库上下文。请使用 USE 命令或提供数据库名。";
        }

        // 权限检查
        String currentUser = getCurrentUser();
        if (!hasDatabasePermission(currentUser, effectiveOwner, effectiveDbName)) {
            return "错误：用户 [" + currentUser + "] 无权访问数据库 [" + effectiveOwner + "." + effectiveDbName + "]。";
        }

        result.append("数据库 [" + effectiveOwner + "." + effectiveDbName + "] 中的表:\n");

        List<String> tables = TableManager.getTables(effectiveOwner, effectiveDbName);
        if (tables == null || tables.isEmpty()) {
            result.append("  (无表)");
        } else {
            for (String tableName : tables) {
                result.append("  - ").append(tableName).append("\n");
            }
        }

        return result.toString();
    }

    public static String getTableInfoAsString(String tableName, String ownerName, String dbName) {
        StringBuilder result = new StringBuilder();
        String effectiveOwner = ownerName;
        String effectiveDbName = dbName;

        if (effectiveDbName == null || effectiveDbName.isEmpty()) {
            effectiveDbName = getCurrentDatabaseName();
            effectiveOwner = getCurrentDatabaseOwner();
        }

        if (effectiveOwner == null && "system_db".equals(effectiveDbName)) {
            effectiveOwner = "system";
        }

        if (tableName == null || tableName.isEmpty() || effectiveDbName == null || effectiveDbName.isEmpty() || effectiveOwner == null || effectiveOwner.isEmpty()) {
            return "错误：必须提供表名、数据库所有者和数据库名。";
        }

        // 权限检查
        String currentUser = getCurrentUser();
        if (!hasDatabasePermission(currentUser, effectiveOwner, effectiveDbName)) {
            return "错误：用户 [" + currentUser + "] 无权访问数据库 [" + effectiveOwner + "." + effectiveDbName + "]。";
        }

        result.append("表 [").append(tableName).append("] 在数据库 [")
                .append(effectiveOwner).append(".").append(effectiveDbName).append("] 中的结构信息:\n");

        DB targetDB = null;
        try {
            targetDB = getDatabase(effectiveOwner, effectiveDbName);

            if (!targetDB.exists("_schema_" + tableName)) {
                return "  表 '" + tableName + "' 的结构信息不存在或表不存在。";
            }

            @SuppressWarnings("unchecked")
            Map<String, String> schema = (Map<String, String>) targetDB
                    .hashMap("_schema_" + tableName, Serializer.STRING, Serializer.STRING)
                    .open();

            if (schema.isEmpty()) {
                result.append("  (表结构为空或未定义)");
            } else {
                result.append("  列名                 | 数据类型\n");
                result.append("  ---------------------|-----------\n");
                for (Map.Entry<String, String> entry : schema.entrySet()) {
                    result.append(String.format("  %-20s | %s\n", entry.getKey(), entry.getValue()));
                }
            }
        } catch (StorageException e) {
            return "显示表结构时出错: " + e.getMessage();
        } catch (Exception e) {
            return "显示表结构时发生意外错误: " + e.getMessage();
        } finally {
            if (targetDB != null) {
                releaseDatabase(effectiveOwner, effectiveDbName);
            }
        }

        return result.toString();
    }



}